﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StackExchange.Redis;

namespace Redis读写分离.Common
{
    public class HealthCheckedRedisManager : RedisReadWriteManager
    {
        private readonly Timer _healthCheckTimer;
        private readonly List<ConnectionMultiplexer> _healthyReadConnections = new List<ConnectionMultiplexer>();
        private Random _random = new Random();

        public HealthCheckedRedisManager(Configuration config, int healthCheckInterval = 30000)
            : base(config)
        {
            // 初始健康连接
            _healthyReadConnections.AddRange(base.GetReadConnections());

            // 定时健康检查
            _healthCheckTimer = new Timer(HealthCheckCallback, null, healthCheckInterval, healthCheckInterval);
        }

        private void HealthCheckCallback(object state)
        {
            var tempHealthyConnections = new List<ConnectionMultiplexer>();

            foreach (var conn in base.GetReadConnections())
            {
                try
                {
                    var server = conn.GetServer(conn.GetEndPoints().First());
                    if (server.IsConnected && !server.IsSlave)
                {
                        tempHealthyConnections.Add(conn);
                    }
                }
                catch
                {
                    // 连接异常，视为不健康
                }
            }

            lock (_healthyReadConnections)
            {
                _healthyReadConnections.Clear();
                _healthyReadConnections.AddRange(tempHealthyConnections);
            }
        }

        public new IDatabase GetReadDatabase(int db = -1)
        {
            lock (_healthyReadConnections)
            {
                if (_healthyReadConnections.Count == 0)
                {
                    return base.GetWriteDatabase(db);
                }

                var index = _random.Next(_healthyReadConnections.Count);
                return _healthyReadConnections[index].GetDatabase(db);
            }
        }

        public override void Dispose()
        {
            _healthCheckTimer?.Dispose();
            base.Dispose();
        }
    }
}
